/*
 * OREKIT-X
 * Copyright 2002-2008 CS Communication & Systemes
 * 
 * Parts of this software package have been licensed to CS
 * Communication & Systemes (CS) under one or more contributor license
 * agreements.  See the NOTICE file distributed with this work for
 * additional information.
 *  
 * This is an experimental copy of OREKIT from www.orekit.org.
 * Please use the original OREKIT from orekit.org for normal work
 * unrelated to this research project.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you
 * may not use this file except in compliance with the License.  You
 * may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
 * implied.  See the License for the specific language governing
 * permissions and limitations under the License.
 */
package ore.attitudes;

import ore.Attitude;
import ore.Frame;
import ore.PositionVelocity;
import ore.time.AbsoluteDate;

import org.apache.commons.math.geometry.Rotation;
import org.apache.commons.math.geometry.RotationOrder;
import org.apache.commons.math.geometry.Vector3D;


/**
 * The attitude law is defined as a rotation offset from local orbital frame.
 * 
 * This rotation can be defined by
 * (NB. local orbital frame is defined as follows)
 * 
 *       Z axis pointed towards central body,
 * 
 *       Y opposite to angular momentum,
 * 
 *       X roughly along velocity (it would be perfectly aligned only
 *       for circular orbits or at perigee and apogee of non-circular
 *       orbits).
 * 
 * @author V&eacute;ronique Pommier-Maurussane
 */
public class LofOffset
    extends Object
    implements ore.AttitudeLaw
{

    /**
     * Attitude law perfectly aligned with the LOF frame.
     */
    public static final LofOffset LOF_ALIGNED =
        new LofOffset(RotationOrder.ZYX, 0., 0., 0.);



    /**
     * Rotation from local orbital frame. 
     */
    private final Rotation offset;


    /** 
     * @param order Order of rotations to use for (alpha1, alpha2, alpha3) composition
     * @param alpha1 Angle of the first elementary rotation
     * @param alpha2 Angle of the second elementary rotation
     * @param alpha3 Angle of the third elementary rotation
     */
    public LofOffset(RotationOrder order, double alpha1,
                     double alpha2, double alpha3)
    {
        super();
        this.offset = new Rotation(order, alpha1, alpha2, alpha3);
    }


    /** 
     * User should check that position/velocity and frame are consistent.
     * 
     * @param date date when system state shall be computed
     * @param pv satellite position/velocity in given frame
     * @param frame the frame in which pv is defined
     * @return satellite attitude state at date
     */
    public Attitude getState(AbsoluteDate date, PositionVelocity pv, Frame frame){
        /*
         * Construction of the local orbital frame
         */
        Vector3D p = pv.getPosition();
        Vector3D v = pv.getVelocity();
        Vector3D momentum = Vector3D.crossProduct(p, v);
        double angularVelocity = (Vector3D.dotProduct(momentum, momentum) / 
                                  Vector3D.dotProduct(p, p));

        Rotation lofRot = new Rotation(p, momentum, Vector3D.MINUS_K, Vector3D.MINUS_J);
        Vector3D spinAxis = new Vector3D(angularVelocity, Vector3D.MINUS_J);
        /*
         * Compose with offset rotation
         */
        return new Attitude(frame, offset.applyTo(lofRot), offset.applyTo(spinAxis));
    }

}
